﻿
#region 作者和版权
/*************************************************************************************
* CLR 版本: 4.0.30319.42000
* 类 名 称: OrmHelper
* 机器名称: SUNTIA-QL
* 命名空间: ServerFramework.ORM
* 文 件 名: OrmHelper
* 创建时间: 2015/9/24 14:52:27
* 作 者: 乔龙 Qiaolong
* 版 权: OrmHelper说明：本代码版权归乔龙所有，使用时必须带上乔龙网站地址 All Rights Reserved (C) 2015 - 2013
* 签 名: To be or not, it is not a problem !
* 网 站: http://www.suntia.net
* 邮 箱: qiaolong306@qq.com 
* 唯一标识： 03d5f458-9e84-41f4-bdb5-687885a446c5 
*
* 登录用户: simida
* 所 属 域: SUNTIA-QL

* 创建年份: 2015
* 修改时间:
* 修 改 人:
* 
************************************************************************************/
#endregion

using System;
using System.Collections.Generic;
using System.Text;
using ServerFramework.Tools;
using System.Reflection;
using fastJSON;
using System.Configuration;
using FastReflectionLib;
using ServerFramework.Db;
using Development.Tools;



namespace ServerFramework.ORM
{
    /// <summary>
    /// ORM 工具类
    /// </summary>
    public static class ORMHelper
    {
        /// <summary>
        /// 检查程序集中的所有表是否创建
        /// </summary>
        public static void CheckAssemblyAllTables()
        {
            try
            {
                CheckDatabase();
                var types = Assembly.GetEntryAssembly().GetTypes();
                var baseType = typeof(DataEntityBase);
                foreach (var ty in types)
                {
                    if (!ty.IsInterface)
                    {
                        if (ty.BaseType == baseType || (ty.BaseType.BaseType != null && ty.BaseType.BaseType == baseType))
                        {
                            DataEntityBase obj = GlobalDefine.CreateObject(ty) as DataEntityBase;
                            if (obj != null)
                            {
                                CheckTable(obj);
                            }
                        }
                    }

                }
            }
            catch (Exception e)
            {
                Log.WriteLog(ELogLevel.LOG_ERROR, e);
            }
        }

        /// <summary>
        /// 检查数据库
        /// </summary>
        private static void CheckDatabase()
        {
            foreach (ConnectionStringSettings connection in ConfigurationManager.ConnectionStrings)
            {
                DbProvider provider = DbHelper.CreateDbProvider(connection);
                if (provider != null)
                {
                    if (!provider.TryOpen())
                    {
                        string connectStr = connection.ConnectionString.ToLower();
                        string[] temp = connectStr.Split(';');
                        connectStr = "";
                        string dbName = "";
                        foreach (var t in temp)
                        {
                            if (!t.Contains("database"))
                            {
                                connectStr += t + ";";
                            }
                            else
                            {
                                dbName = t.Replace("database=", "");
                            }
                        }
                        provider = DbHelper.CreateDbProvider(connection, connectStr);
                        if (provider.Open())
                        {
                            string s = string.Format("CREATE DATABASE `{0}` CHARACTER SET utf8 COLLATE utf8_general_ci", dbName);
                            provider.ExecuteNonQuery(s);
                            provider.Close();
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 检查数据表，如果不存在就创建
        /// </summary>
        /// <param name="table"></param>
        public static void CheckTable(DataEntityBase table)
        {

            DbProvider provider = DbHelper.CreateDbProvider(ConfigUtil.GetConnectionSetting(table.GetDbName()));
            if (provider == null)
            {
                return;
            }

            if (!provider.Open())
            {
                return;
            }
            Type tableType = table.GetType();
            string TableName = tableType.Name;

            //检查表是否存在
            bool isTableExist = provider.IsTableExist(TableName);
            if (!isTableExist)
            {
                List<DbColum> cols = DbColum.CreateDbColums(tableType);
                StringBuilder command = new StringBuilder();
                command.AppendFormat("CREATE TABLE {0}(", TableName);

                foreach (DbColum c in cols)
                {
                    command.AppendFormat(DbColum.CreateColumSql(c) + ",");
                }
                command.Remove(command.Length - 1, 1);
                command.AppendFormat(")CharSet=utf8;");

                //创建表
                provider.ExecuteNonQuery(command.ToString());
                Log.WriteLog(ELogLevel.LOG_INFO, string.Format("Create table {0} Success", TableName));
            }
            else
            {
                CheckCols(provider, tableType, table);
            }
            provider.Close();
        }


        /// <summary>
        /// 检查列是否正常
        /// </summary>
        /// <param name="provider"></param>
        /// <param name="tableType"></param>
        private static void CheckCols(DbProvider provider, Type tableType, DataEntityBase table)
        {
            string dbName = table.GetDbName();
            dbName = ConfigUtil.GetDbNameFromDbEntityDbName(dbName);

            string colSql = string.Format("select column_name from information_schema.columns where TABLE_SCHEMA = '{0}' and  table_name = '{1}'", dbName, tableType.Name);
            List<string> listCol = new List<string>();
            if (provider.ExecuteQuery(colSql))
            {
                while (provider.Read())
                {
                    listCol.Add(provider.Read(0).ToString());
                }
            }
            provider.EndExecuteQuery();
            //获取类型的字段
            List<PropertyInfo> listCol1 = new List<PropertyInfo>();
            PropertyInfo[] fields = tableType.GetProperties();
            for (int i = 0; i < fields.Length; ++i)
            {
                PropertyInfo fd = fields[i];
                listCol1.Add(fd);
            }

            //先找到要删除的字段
            List<string> delCols = new List<string>();
            foreach (var v in listCol)
            {
                var temp = listCol1.Find(p => p.Name == v);
                if (temp == null)
                {
                    delCols.Add(v);
                }
            }
            //要增加的字段
            List<PropertyInfo> addCols = new List<PropertyInfo>();
            foreach (var v in listCol1)
            {
                if (!listCol.Contains(v.Name))
                {
                    addCols.Add(v);
                }
            }
            //删除列
            foreach (var v in delCols)
            {
                string sql = string.Format("alter table {0} drop column {1}", tableType.Name, v);
                provider.ExecuteNonQuery(sql);
            }

            //增加列
            foreach (var v in addCols)
            {
                DbColum col = DbColum.CreateDbColum(v);
                if (col != null)
                {
                    string sql = string.Format("alter table {0} add column {1}", tableType.Name, DbColum.CreateColumSql(col));
                    provider.ExecuteNonQuery(sql);
                }
            }
        }

        /// <summary>
        /// 根据类型创建数据库连接
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static DbProvider CreateDbProvider(Type type)
        {
            DbProvider provider = null;
            DbDataAttribute attr = Attribute.GetCustomAttribute(type, typeof(DbDataAttribute)) as DbDataAttribute;
            if (attr != null)
            {
                var config = ConfigUtil.GetConnectionSetting(attr.DbName);
                if (config != null)
                {
                    provider = DbHelper.CreateDbProvider(config);
                }
            }
            return provider;
        }

        /// <summary>
        /// 是否为基本属性
        /// </summary>
        /// <param name="fd"></param>
        /// <returns></returns>
        private static bool IsBasePropertyType(PropertyInfo fd)
        {
            if (fd.PropertyType == typeof(Int32)
                || fd.PropertyType == typeof(UInt32)
                || fd.PropertyType == typeof(Single)
                || fd.PropertyType == typeof(String)
                || fd.PropertyType == typeof(Int64)
                || fd.PropertyType == typeof(UInt64)
                || fd.PropertyType == typeof(Boolean)
                || fd.PropertyType == typeof(Decimal)
                || fd.PropertyType == typeof(Double)
                || fd.PropertyType == typeof(Int16)
                || fd.PropertyType == typeof(UInt16)
                || fd.PropertyType == typeof(Byte)
                || fd.PropertyType == typeof(Byte[])
                || fd.PropertyType == typeof(Guid)
                || fd.PropertyType == typeof(DateTime)
                                            )
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// set obj property
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="dbVal"></param>
        /// <param name="fd"></param>
        public static void SetProperty(object obj, object dbVal, PropertyInfo fd)
        {
            object val = dbVal;
            if (IsBasePropertyType(fd))
            {
                try
                {
                    if (val != DBNull.Value)
                    {
                        val = Convert.ChangeType(val, fd.PropertyType);
                        fd.FastSetValue(obj, val);
                    }
                    else
                    {
                        if(fd.PropertyType == typeof(String))
                        {
                            fd.FastSetValue(obj, "");
                        }
                        else if(fd.PropertyType == typeof(Guid))
                        {
                            fd.FastSetValue(obj, Guid.NewGuid());
                        }
                        else if (fd.PropertyType == typeof(Boolean))
                        {
                            fd.FastSetValue(obj, false);
                        }
                    }
                }
                catch (Exception e)
                {
                    Log.WriteLog(ELogLevel.LOG_ERROR, string.Format("{0};name[{1}]:val[{2}]", e.Message, fd.Name, val));
                }
            }
            else
            {
                try
                {
                    if (val != DBNull.Value)
                    {
                        val = fastJSON.JSON.ToObject(val.ToString(), fd.PropertyType);
                    }
                    else
                    {
                        val = GlobalDefine.CreateObject(fd.PropertyType);
                    }
                    fd.FastSetValue(obj, val);
                }
                catch (Exception e)
                {
                    Log.WriteLog(ELogLevel.LOG_ERROR, string.Format("{0};name[{1}]:val[{2}]", e.Message, fd.Name, val));
                }
            }
        }

        /// <summary>
        /// db to obj
        /// </summary>
        /// <param name="db"></param>
        /// <param name="obj"></param>
        public static void DbToObj(DbProvider db, object obj)
        {
            Type type = obj.GetType();
            PropertyInfo[] fields = type.GetProperties();
            for (int i = 0; i < fields.Length; ++i)
            {
                PropertyInfo fd = fields[i];
                object dbVal = db.Read(fd.Name);
                SetProperty(obj, dbVal, fd);
            }
        }

        /// <summary>
        /// 获取entity 插入sql
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static string GetEntityInsertSql(DataEntityBase entity)
        {
            Type type = entity.GetType();
            PropertyInfo[] fields = type.GetProperties();
            string values = "";
            var idFd = fields[fields.Length - 1];
            values += GetSqlValStringByProperties(entity, idFd);
            values += ",";
            for (int i = 0; i < fields.Length - 1; ++i)
            {
                PropertyInfo fd = fields[i];
                values += GetSqlValStringByProperties(entity, fd);
                if (i != fields.Length - 2)
                {
                    values += ",";
                }
            }
            return string.Format("insert into {0} values ({1})", entity.GetType().Name, values);
        }

        /// <summary>
        /// 获取enity更新sql
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static string GetEntityUpdateSql(DataEntityBase entity)
        {
            string sets = "";
            Type type = entity.GetType();
            PropertyInfo[] fields = type.GetProperties();
            for (int i = 0; i < fields.Length; ++i)
            {
                PropertyInfo fd = fields[i];
                sets += fd.Name + "=" + GetSqlValStringByProperties(entity, fd);
                if (i != fields.Length - 1)
                {
                    sets += ",";
                }
            }
            return string.Format("update {0} set {1} where id = {2}", entity.GetType().Name, sets, entity.id);
        }

        private static string GetSqlValStringByProperties(object obj, PropertyInfo fd)
        {
            if (fd.PropertyType == typeof(Int32)
                || fd.PropertyType == typeof(Single)
                || fd.PropertyType == typeof(Int64)
                || fd.PropertyType == typeof(UInt64)
                || fd.PropertyType == typeof(Boolean)
                || fd.PropertyType == typeof(Decimal)
                || fd.PropertyType == typeof(Double)
                || fd.PropertyType == typeof(UInt32)
                || fd.PropertyType == typeof(Int16)
                || fd.PropertyType == typeof(UInt16)
                || fd.PropertyType == typeof(Byte)
                || fd.PropertyType == typeof(Byte[])
                                           )
            {
                return string.Format("{0}", fd.FastGetValue(obj));
            }
            else if (fd.PropertyType == typeof(string)
                    || fd.PropertyType == typeof(Guid)
                    || fd.PropertyType == typeof(DateTime)
                )
            {
                return string.Format("'{0}'", fd.FastGetValue(obj));
            }
            else
            {
                return string.Format("'{0}'", JSON.ToJSON(fd.FastGetValue(obj)));
            }
        }

        /// <summary>
        /// 获取entiy 删除sql
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static string GetEntityDeleteSql(DataEntityBase entity)
        {
            return string.Format("delete from {0} where id = {1}", entity.GetType().Name, entity.id); ;
        }

        /// <summary>
        ///从数据库里面获取数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T GetDbEntity<T>(DbProvider dbProvider, long id) where T : DataEntityBase, new()
        {
            string sql = string.Format("select * from {0} where id = {1}", typeof(T).Name, id);
            T t = null;
            if (dbProvider.ExecuteQuery(sql))
            {
                if (dbProvider.Read())
                {
                    t = new T();
                    DbToObj(dbProvider, t);
                }
            }
            dbProvider.EndExecuteQuery();
            return t;
        }

        public static List<T> GetDbEntityList<T>(DbProvider dbProvider) where T : DataEntityBase, new()
        {
            string sql = string.Format("select * from {0}", typeof(T).Name);
            List<T> list = new List<T>();
            if (dbProvider.ExecuteQuery(sql))
            {
                while (dbProvider.Read())
                {
                    T t = new T();
                    DbToObj(dbProvider, t);
                    list.Add(t);
                }
            }
            dbProvider.EndExecuteQuery();
            return list;
        }

        public static List<DataEntityBase> GetDbEntityList(Type type)
        {
            string sql = string.Format("select * from {0}", type.Name);
            List<DataEntityBase> list = new List<DataEntityBase>();
            var dbProvider = CreateDbProvider(type);
            if (dbProvider != null)
            {
                if (dbProvider.Open())
                {
                    if (dbProvider.ExecuteQuery(sql))
                    {
                        while (dbProvider.Read())
                        {
                            DataEntityBase obj = GlobalDefine.CreateObject(type) as DataEntityBase;
                            DbToObj(dbProvider, obj);
                            list.Add(obj);
                        }
                    }
                }
                dbProvider.EndExecuteQuery();
                dbProvider.Close();
            }
            return list;
        }
        public static List<T> GetDbEntityList<T>(List<long> ids) where T : DataEntityBase
        {
            Type type = typeof(T);
            string sql = string.Format("select * from {0}", type.Name);
            sql += " where id in (";
            for (int i = 0; i < ids.Count; ++i)
            {
                sql += ids[i].ToString();
                if (i != ids.Count - 1)
                {
                    sql += ",";
                }
                else
                {
                    sql += ")";
                }
            }

            List<T> list = new List<T>();
            var dbProvider = CreateDbProvider(type);
            if (dbProvider != null)
            {
                if (dbProvider.Open())
                {
                    if (dbProvider.ExecuteQuery(sql))
                    {
                        while (dbProvider.Read())
                        {
                            var obj = GlobalDefine.CreateObject(type) as T;
                            DbToObj(dbProvider, obj);
                            list.Add(obj);
                        }
                    }
                }
                dbProvider.EndExecuteQuery();
                dbProvider.Close();
            }
            return list;
        }

        public static void RemoveIds<T>(List<T> entitys) where T : DataEntityBase
        {
            Type type = typeof(T);
            string sql = string.Format("delete from {0}", type.Name);
            sql += " where id in (";
            for (int i = 0; i < entitys.Count; ++i)
            {
                sql += entitys[i].id.ToString();
                if (i != entitys.Count - 1)
                {
                    sql += ",";
                }
                else
                {
                    sql += ")";
                }
            }

            List<T> list = new List<T>();
            var dbProvider = CreateDbProvider(type);
            if (dbProvider != null)
            {
                if (dbProvider.Open())
                {
                    dbProvider.ExecuteNonQuery(sql);
                }
                dbProvider.Close();
            }
        }



        public static List<Type> GetTypesFromCurrAssemblyByBase(Type baseType)
        {
            List<Type> types = new List<Type>();
            var typeArray = Assembly.GetEntryAssembly().GetTypes();
            foreach (var ty in typeArray)
            {
                if (ty.BaseType == baseType)
                {
                    types.Add(ty);
                }
            }
            return types;
        }

    }
}


